/* eslint-disable prefer-destructuring */
import { clone, mergeInLeft } from '@ibiz-template/core';
import {
  AfterCallback,
  ControllerEvent,
  IFilterNode,
  IFilterNodeGroup,
  ISearchCond,
  ISearchCondEx,
  ISearchCondField,
  ISearchCondGroup,
  ISearchCondItems,
  isSimpleItems,
  ITabExpPanelController,
  ItemsValueOPs,
  ScriptFactory,
  SearchBarController,
  SearchBarFilterItemsController,
  SearchBarFilterSimpleItemsController,
  SearchCondEx2filterNode,
  validateFilterNodes,
  ValueOP,
} from '@ibiz-template/runtime';
import { ISearchBarFilter } from '@ibiz/model-core';
import { isString } from 'lodash-es';
import {
  FilterItemController,
  IFilterNodeItem,
} from './filter-item.controller';
import { FilterSearchBarService } from './filter-search-bar.service';
import {
  GroupType,
  ICondition,
  IFilterBarEvent,
  IFilterData,
  IFilterSearchBarState,
  IGroupData,
} from './interface';

export const ScriptValueRegex = /\$\{[^}]*\}/;

/**
 * 过滤搜索栏控制器
 */
export class FilterSearchBarController extends SearchBarController {
  declare state: IFilterSearchBarState;

  declare service: FilterSearchBarService;

  get _evt(): ControllerEvent<IFilterBarEvent> {
    return this.evt;
  }

  /**
   * 分页导航栏
   *
   * @readonly
   * @type {ITabExpPanelController}
   * @memberof FilterSearchBarController
   */
  get tabExpPanel(): ITabExpPanelController {
    return this.view.getController('tabexppanel') as ITabExpPanelController;
  }

  /**
   * 初始化state的属性
   *
   * @protected
   * @memberof FilterSearchBarController
   */
  protected initState(): void {
    super.initState();
    this.state.sysFilter = [];
    this.state.fieldFilter = [];
    this.state.groupFilter = [];
    this.state.conds = {};
    this.state.selectGroup = undefined;
    this.state.applyFilter = { id: 'draft', condition: [] };
  }

  /**
   * 生命周期-创建完成
   */
  protected async onCreated(): Promise<void> {
    await super.onCreated();
    if (this.view.model.codeName) {
      this.service = new FilterSearchBarService(
        this.model,
        this.view.model.codeName.toLowerCase(),
      );
      await this.service.init(this.context);
    }
    this.initModelFilter();
    await this.initGroupFilter();
    this.setDefaultSelect();
  }

  /**
   * 初始化过滤项控制器（重写）
   * - 将常规属性过滤项控制器改为FilterItemController
   * @protected
   * @return {*}  {Promise<void>}
   * @memberof FilterSearchBarController
   */
  protected async initSearchBarFilters(): Promise<void> {
    if (this.searchBarFilters?.length) {
      const itemsMap = new Map<string, ISearchBarFilter[]>();
      this.searchBarFilters.forEach(item => {
        // 整理exists或者NOTEXISTS的模型
        if (
          item.defsearchMode?.valueOP &&
          ItemsValueOPs.includes(item.defsearchMode.valueOP)
        ) {
          if (isSimpleItems(item)) {
            this.filterControllers.push(
              new SearchBarFilterSimpleItemsController(
                item,
                this.appDataEntity,
                this.context,
                this.params,
              ),
            );
            return;
          }

          const key = `${item.appDEFieldId}_${item.defsearchMode.valueOP}`;
          if (!itemsMap.has(key)) {
            itemsMap.set(key, []);
          }
          itemsMap.get(key)!.push(item);
          return;
        }

        // 常规的属性过滤项
        const filterController = new FilterItemController(
          item,
          this.appDataEntity,
          this.context,
          this.params,
        );
        this.filterControllers.push(filterController);
      });

      // 初始化SearchBarFilterItemsController
      if (itemsMap.size > 0) {
        itemsMap.forEach(items => {
          const filterController = new SearchBarFilterItemsController(
            items,
            this.appDataEntity,
            this.context,
            this.params,
          );
          this.filterControllers.push(filterController);
        });
      }

      await Promise.all(
        this.filterControllers.map(controller => controller.init()),
      );
    }
  }

  /**
   * 初始化过滤器模型
   * - 系统过滤器模型
   * - 字段过滤器模型
   *
   * @protected
   * @memberof FilterSearchBarController
   */
  protected initModelFilter(): void {
    try {
      this.state.sysFilter =
        this.model.searchBarGroups?.filter(g => !(g as IData).userTag) || [];
      const fieldName: string[] = [];
      this.state.sysFilter.forEach(s => {
        if (s.data) {
          const item = JSON.parse(s.data);
          if (item.theme_model?.searchconds) {
            const { searchconds } = item.theme_model.searchconds[0];
            if (searchconds && searchconds.length > 0) {
              searchconds.forEach((cond: IData) => {
                if (cond.fieldname && !fieldName.includes(cond.fieldname)) {
                  fieldName.push(cond.fieldname);
                }
              });
            }
          }
        }
      });
      this.state.fieldFilter =
        this.model.searchBarFilters?.filter(
          f =>
            !f.hidden &&
            (!f.appDEFieldId || !fieldName.includes(f.appDEFieldId)),
        ) || [];
    } catch (error) {
      ibiz.log.error(`初始化过滤数据异常:`, error);
    }
  }

  /**
   * 初始化分组过滤
   *
   * @return {*}  {Promise<void>}
   * @memberof FilterSearchBarController
   */
  async initGroupFilter(): Promise<void> {
    this.state.groupFilter =
      this.model.searchBarGroups
        ?.filter(g => (g as IData).userTag)
        .map((group, index) => {
          let searchconds: IFilterNode[] | undefined;
          if (group.data) {
            try {
              const item = JSON.parse(group.data);
              if (item.theme_model?.searchconds) {
                searchconds = item.theme_model.searchconds.map(
                  (cond: ISearchCondEx) => SearchCondEx2filterNode(cond),
                );
              }
            } catch (error) {
              ibiz.log.error(
                ibiz.i18n.t('runtime.controller.control.searchBar.JSONFormat', {
                  data: group.data,
                }),
                error,
              );
            }
          }
          return {
            name: group.id!,
            caption: group.caption!,
            collect: false,
            searchconds,
            defaultSelect: false,
            order: (index + 1) * 100,
            filter: [],
            groupType: (group as IData).userTag,
          };
        }) || [];
    const res = await this.service.fetch();
    if (res.ok) {
      res.data.forEach((group: IData) => {
        const exists = this.state.groupFilter.find(
          item => item.name === group.name,
        );
        if (exists) {
          mergeInLeft(exists, group);
        } else {
          const tempMaxOrderIndex = this.state.groupFilter.reduce(
            (maxIndex, item, currentIndex) =>
              item.order > this.state.groupFilter[maxIndex].order
                ? currentIndex
                : maxIndex,
            0,
          );
          this.state.groupFilter.push({
            ...(group as IGroupData),
            order: (tempMaxOrderIndex + 2) * 100,
            filter: [],
            groupType: GroupType.PRIVATE,
          });
        }
      });
    }
    // 按照 order 属性从小到大排序
    this.state.groupFilter.sort((a, b) => a.order - b.order);
    // 更新 order 属性的值
    this.state.groupFilter.forEach((item, index) => {
      item.order = (index + 1) * 100;
    });
    // 设置默认选中
    const defaultGroup = this.model.searchBarGroups?.find(
      item => item.defaultGroup && (item as IData).userTag,
    );
    const defaultFilter = this.state.groupFilter.find(
      g => g.name === defaultGroup?.id,
    );
    if (defaultFilter) {
      defaultFilter.defaultSelect = true;
    } else if (this.state.groupFilter[0]) {
      this.state.groupFilter[0].defaultSelect = true;
    }
  }

  /**
   * 设置默认选中之后刷新分页导航栏
   *
   * @memberof FilterSearchBarController
   */
  setDefaultSelect(): void {
    let defaultSelect: IGroupData | undefined;
    if ((ibiz.env as IData).simplemode) {
      defaultSelect = this.state.groupFilter.find(item => item.name === 'all');
    } else {
      defaultSelect = this.state.groupFilter.find(item => item.defaultSelect);
    }
    if (defaultSelect) {
      this.onGroupClick(defaultSelect);
      if (this.tabExpPanel) {
        this.tabExpPanel.state.expViewParams = this.getFilterParams();
        this.tabExpPanel.refresh();
      }
    }
  }

  /**
   * 新建过滤分组
   *
   * @param {IData} group 分组数据
   * @return {*}  {Promise<void>}
   * @memberof FilterSearchBarController
   */
  async onNewGroup(group: IData): Promise<void> {
    const res = await this.service.createGroup(group);
    if (res.ok) {
      const tempMaxOrderIndex = this.state.groupFilter.reduce(
        (maxIndex, item, currentIndex) =>
          item.order > this.state.groupFilter[maxIndex].order
            ? currentIndex
            : maxIndex,
        0,
      );
      this.state.groupFilter.push({
        ...(res.data as IGroupData),
        order: (tempMaxOrderIndex + 2) * 100,
        filter: [],
        groupType: GroupType.PRIVATE,
      });
      ibiz.message.success(`新建分组 ${group.caption}`);
    }
  }

  /**
   * 处理分组收藏
   *
   * @param {IGroupData} item 分组数据
   * @param {boolean} state 收藏状态
   * @return {*}  {Promise<void>}
   * @memberof FilterSearchBarController
   */
  async handleGroupCollect(item: IGroupData, state: boolean): Promise<void> {
    item.collect = state;
    if (item.id) {
      await this.service.update(item.id, item);
    } else {
      const res = await this.service.createGroup(item);
      if (res.ok) {
        const savedGroup = this.state.groupFilter.find(
          group => group.name === res.data.name,
        );
        if (savedGroup) {
          mergeInLeft(savedGroup, res.data);
        }
      }
    }
    ibiz.message.success(`${item.caption}${state ? '收藏' : '取消收藏'}成功 `);
  }

  /**
   * 分组点击
   *
   * @param {IGroupData} item
   * @return {*}  {Promise<void>}
   * @memberof FilterSearchBarController
   */
  async onGroupClick(item: IGroupData): Promise<void> {
    this.state.selectGroup = item;
    this._evt.emit('onGroupChange', { group: item });
    if (item.id) {
      const res = await this.service.get(item.id);
      mergeInLeft(item, res.data);
    }
    this.onClearFilter();
  }

  /**
   * 过滤器点击
   *
   * @param {IFilterData} item 过滤器数据
   * @memberof FilterSearchBarController
   */
  onFilterClick(item: IFilterData): void {
    const filter = clone(item);
    // 将过滤器中的搜索条件应用
    const conds = {};
    filter.condition.forEach(c => {
      if (!c.searchconds.nodeType) {
        Object.assign(c.searchconds, { nodeType: 'FIELD' });
      }
      Object.assign(conds, { [c.id]: c.searchconds });
    });
    this.state.conds = conds;
    this.state.applyFilter = filter;
    this.onSearch();
  }

  /**
   * 应用过滤器
   *
   * @param {ICondition[]} condition 条件项
   * @memberof FilterSearchBarController
   */
  onApplyFilter(condition: ICondition[]): void {
    // 将未应用的搜索条件删除
    const keys = condition.map(c => c.id);
    if (Object.keys(this.state.conds).length > 0) {
      Object.keys(this.state.conds).forEach(key => {
        if (!keys.includes(key)) {
          delete this.state.conds[key];
        }
      });
    }
    this.state.applyFilter.condition = condition;
    this.onSearch();
  }

  /**
   * 获取当前分组默认条件
   *
   * @return {*}  {IFilterNodeGroup[]}
   * @memberof FilterSearchBarController
   */
  getOriginFilterNodes(): IFilterNodeGroup[] {
    const { selectGroup } = this.state;
    const rootNode: IFilterNodeGroup = {
      nodeType: 'GROUP',
      logicType: 'AND',
      children: [],
    };
    if (selectGroup?.searchconds) {
      rootNode.children = [...selectGroup.searchconds];
    }
    return [rootNode];
  }

  /**
   * 搜索
   *
   * @memberof FilterSearchBarController
   */
  onSearch(): void {
    const filterNodes = this.getOriginFilterNodes();
    const filterNode = filterNodes[0];
    const conds = Object.values(this.state.conds);
    if (conds.length > 0) {
      conds.forEach(item => {
        if (item.leaf) {
          filterNode.children.push(item);
        } else {
          item.children.forEach((c: IFilterNode) => {
            filterNode.children.push(c);
          });
        }
      });
    }
    this.state.filterNodes = filterNodes;
    this.evt.emit('onSearch', undefined);
  }

  /**
   * 清除过滤器
   *
   * @memberof FilterSearchBarController
   */
  onClearFilter(): void {
    this.state.applyFilter = {
      id: 'draft',
      condition: [],
    };
    this.state.conds = {};
    this.onSearch();
  }

  /**
   * 重命名过滤器
   *
   * @param {IFilterData} filter
   * @memberof FilterSearchBarController
   */
  onRenameFilter(filter: IFilterData): void {
    this._evt.emit('onRenameFilter', { filter });
  }

  /**
   * 保存
   *
   * @param {boolean} [saveAs=false]
   * @return {*}  {Promise<void>}
   * @memberof FilterSearchBarController
   */
  async save(saveAs: boolean = false): Promise<void> {
    const { applyFilter } = this.state;
    const isSaveAs = applyFilter.id === 'draft' || saveAs;
    if (isSaveAs) {
      this._evt.emit('onSaveFilter', { filter: applyFilter });
    } else {
      await this.onSaveFilter(applyFilter);
    }
  }

  /**
   * 保存过滤器
   *
   * @param {IFilterData} filter
   * @return {*}  {Promise<void>}
   * @memberof FilterSearchBarController
   */
  async onSaveFilter(filter: IFilterData): Promise<void> {
    const { selectGroup } = this.state;
    if (selectGroup) {
      const index = selectGroup.filter.findIndex(f => f.id === filter.id);
      if (index > -1) {
        selectGroup.filter[index] = filter;
      } else {
        selectGroup.filter.push(filter);
      }
      if (selectGroup.id) {
        await this.service.update(selectGroup.id, selectGroup);
        ibiz.message.success(`过滤器${filter.caption}保存成功`);
      } else {
        const res = await this.service.createGroup(selectGroup);
        if (res.ok) {
          const savedGroup = this.state.groupFilter.find(
            group => group.name === res.data.name,
          );
          if (savedGroup) {
            mergeInLeft(savedGroup, res.data);
          }
          ibiz.message.success(`过滤器${filter.caption}保存成功`);
        }
      }
    }
  }

  /**
   * 删除过滤器
   *
   * @param {IFilterData} filter
   * @return {*}  {Promise<void>}
   * @memberof FilterSearchBarController
   */
  async onRemoveFilter(filter: IFilterData): Promise<void> {
    const { selectGroup, applyFilter } = this.state;
    if (selectGroup) {
      const index = selectGroup.filter.findIndex(f => f.id === filter.id);
      if (index > -1) {
        if (filter.id === applyFilter.id) {
          this.state.applyFilter = {
            id: 'draft',
            condition: [],
          };
        }
        selectGroup.filter.splice(index, 1);
        if (selectGroup.id) {
          await this.service.update(selectGroup.id, selectGroup);
        }
      }
    }
  }

  /**
   * 计算过滤项参数（重写）
   * - 特殊处理复合编辑器项值变更
   * @return {*}  {(IData[] | undefined)}
   * @memberof FilterSearchBarController
   */
  calcFilters(): IData[] | undefined {
    if (!this.enableFilter) {
      return;
    }
    const searchconds = this.calcSearchConds(this.state.filterNodes, {
      after: (node, cond) => {
        if (node.nodeType === 'FIELD' && isString(node.value)) {
          if (ScriptValueRegex.test(node.value)) {
            (cond as ISearchCondField).value = ScriptFactory.execSingleLine(
              `\`${node.value}\``,
              {
                ...this.getEventArgs(),
              },
            );
          }
        }
      },
    });

    return searchconds;
  }

  /**
   * 计算搜索条件
   * - 特殊处理复合编辑器项值变更
   * @param {IFilterNode[]} filterNodes
   * @param {{ after: AfterCallback }} [opts]
   * @return {*}  {(ISearchCond[] | undefined)}
   * @memberof FilterSearchBarController
   */
  calcSearchConds(
    filterNodes: IFilterNode[],
    opts?: { after: AfterCallback },
  ): ISearchCond[] | undefined {
    const { pass } = validateFilterNodes(filterNodes);
    if (!pass) {
      return;
    }
    const result: ISearchCond[] = [];
    filterNodes.forEach(node => {
      const filter = this.filterNode2SearchCond(node, opts);
      result.push(...filter);
    });
    return result;
  }

  /**
   * 过滤节点数据转搜索条件
   *
   * @param {IFilterNode} filterNode
   * @param {{ after: AfterCallback }} [opts]
   * @return {*}  {ISearchCond[]}
   * @memberof FilterSearchBarController
   */
  filterNode2SearchCond(
    filterNode: IFilterNode,
    opts?: { after: AfterCallback },
  ): ISearchCond[] {
    const result: ISearchCond[] = [];
    if (filterNode.nodeType === 'GROUP') {
      // 分组
      const temp: ISearchCondGroup = {
        condop: filterNode.logicType,
        condtype: 'GROUP',
      };
      if (filterNode.children.length > 0) {
        temp.searchconds = [];
        filterNode.children.forEach(child => {
          const filter = this.filterNode2SearchCond(child, opts);
          temp.searchconds?.push(...filter);
        });
      }
      result.push(temp);

      // 是否取反
      if (filterNode.notMode) {
        temp.notmode = filterNode.notMode;
      }
    } else if (filterNode.nodeType === 'FIELD') {
      const editorItems = (filterNode as IFilterNodeItem).editorItems;
      if (editorItems) {
        Object.keys(editorItems).forEach(key => {
          const c = this.filterControllers.find(v => v.model.id! === key);
          if (c) {
            result.push({
              condtype: 'DEFIELD',
              fieldname: c.fieldName,
              value: editorItems[key],
              condop: c.valueOP as ValueOP,
            });
          }
        });
      } else {
        // 属性
        const temp: ISearchCondField = {
          condtype: 'DEFIELD',
          fieldname: filterNode.field!,
          value: filterNode.value,
          condop: filterNode.valueOP!,
        };

        // 值项
        if (filterNode.valueItem) {
          temp.value = filterNode.valueItem;
        }
        result.push(temp);
      }
    } else {
      // ITEMS
      const temp: ISearchCondItems = {
        condop: filterNode.valueOP!,
        fieldname: filterNode.field!,
        condtype: 'ITEMS',
      };
      if (filterNode.children.length > 0) {
        temp.searchconds = [];
        filterNode.children.forEach(child => {
          const filter = this.filterNode2SearchCond(child, opts);
          temp.searchconds?.push(...filter);
        });
      }
      result.push(temp);
    }

    // 执行额外后续处理
    if (opts?.after) {
      result.forEach(v => {
        opts.after(filterNode, v);
      });
    }

    return result;
  }
}
